package com.company.game01;

import cn.hutool.core.util.RandomUtil;

import java.awt.*;
import java.util.LinkedList;
import java.util.List;

import static com.company.game01.MyUtil.*;

public class Tank {
    protected static final Image[] heroImages = {
            getImage("/static/p1tankU.gif"),
            getImage("/static/p1tankD.gif"),
            getImage("/static/p1tankL.gif"),
            getImage("/static/p1tankR.gif"),
    };

    protected static final Image[] enemyImages = {
            getImage("/static/enemy_u.gif"),
            getImage("/static/enemy_d.gif"),
            getImage("/static/enemy_l.gif"),
            getImage("/static/enemy_r.gif"),
    };

    public static final int DIR_UP = 0;
    public static final int DIR_DOWN = 1;
    public static final int DIR_LEFT = 2;
    public static final int DIR_RIGHT = 3;

    public static final int RADIUS = 25;
    public static final int DEFAULT_SPEED = 5;

    public static final int STATE_STAND = 0;
    public static final int STATE_MOVE = 1;
    public static final int STATE_DIE = 2;

    public static final int DEFAULT_HP = 1000;

    private int x, y, dir;
    private String name = getRandomName();
    private int state = STATE_STAND;
    private int speed = DEFAULT_SPEED;
    private int hp = DEFAULT_HP;
    private Color color = this instanceof EnemyTank ? Color.GREEN : Color.YELLOW;
    private boolean visible = true;

    private final List<Bullet> bullets = new LinkedList<>();
    private final BloodBar bloodBar = new BloodBar();
    private static final ObjectPool<Bullet> BULLET_POOL = new ObjectPool<>(Bullet.class);

    public Tank() {
    }

    public Tank(int x, int y, int dir, String name) {
        this.x = x;
        this.y = y;
        this.dir = dir;
        this.name = name == "" ? getRandomName() : name;
    }

    public void draw(Graphics g) {
        drawTank(g);
        drawBullets(g);
        bloodBar.draw(g);
        logic();
    }

    private int preX = -1, preY = -1;

    public void setPreX(int preX) {
        this.preX = preX;
    }

    public void setPreY(int preY) {
        this.preY = preY;
    }

    public void back() {
        if (preX != -1 && preY != -1) {
            x = preX;
            y = preY;
        }
    }

    private void move() {
        preX = x;
        preY = y;
        switch (dir) {
            case DIR_UP:
                if (y > RADIUS + MyFrame.TOP + Tank.BloodBar.BAR_HEIGHT * 6) y -= speed;
                break;
            case DIR_DOWN:
                if (y + RADIUS < FRAME_HEIGHT) y += speed;
                break;
            case DIR_LEFT:
                if (x > RADIUS) x -= speed;
                break;
            case DIR_RIGHT:
                if (x + RADIUS < FRAME_WIDTH) x += speed;
                break;
        }
    }

    public Rectangle getRect() {
        return new Rectangle(x - RADIUS, y - RADIUS, RADIUS << 1, RADIUS << 1);
    }

    /*public boolean isTouchTank() {
        for (int i = 0; i < MyFrame.TANKS.size(); i++) {
            Tank tank = MyFrame.TANKS.get(i);
            if (this == tank) continue;
            if (dir == DIR_UP) {
                if (tank.dir == DIR_UP || tank.dir == DIR_DOWN) { // 上下
                    if (x - RADIUS >= tank.x - RADIUS && x - RADIUS <= tank.x + RADIUS // tank.x的范围【tank.x,tank.x+60】 tank.y的范围【tank.y,tank.y+60】
                            && y - RADIUS >= tank.y - RADIUS && y - RADIUS <= tank.y + RADIUS) { // 当前坦克左上角坐标【x,y】
                        return true;
                    }
                    if (x + RADIUS >= tank.x - RADIUS && x + RADIUS <= tank.x + RADIUS
                            && y - RADIUS >= tank.y - RADIUS && y - RADIUS <= tank.y + RADIUS) { // 当前坦克右上角坐标【x+60,y】
                        return true;
                    }
                } else { // 左右
                    if (x - RADIUS >= tank.x - RADIUS && x - RADIUS <= tank.x + RADIUS
                            && y - RADIUS >= tank.y - RADIUS && y - RADIUS <= tank.y + RADIUS) {
                        return true;
                    }
                    if (x + RADIUS >= tank.x - RADIUS && x + RADIUS <= tank.x + RADIUS
                            && y - RADIUS >= tank.y - RADIUS && y - RADIUS <= tank.y + RADIUS) {
                        return true;
                    }
                }
            } else if (dir == DIR_DOWN) {
                if (tank.dir == DIR_UP || tank.dir == DIR_DOWN) { // 上下
                    if (x - RADIUS >= tank.x - RADIUS && x - RADIUS <= tank.x + RADIUS
                            && y + RADIUS >= tank.y - RADIUS && y + RADIUS <= tank.y + RADIUS) {
                        return true;
                    }
                    if (x + RADIUS >= tank.x - RADIUS && x + RADIUS <= tank.x + RADIUS
                            && y + RADIUS >= tank.y - RADIUS && y + RADIUS <= tank.y + RADIUS) {
                        return true;
                    }
                } else { // 左右
                    if (x - RADIUS >= tank.x && x - RADIUS <= tank.x + RADIUS
                            && y + RADIUS >= tank.y && y + RADIUS <= tank.y + RADIUS) {
                        return true;
                    }
                    if (x + RADIUS >= tank.x && x + RADIUS <= tank.x + RADIUS
                            && y + RADIUS >= tank.y && y + RADIUS <= tank.y + RADIUS) {
                        return true;
                    }
                }
            } else if (dir == DIR_LEFT) {
                if (tank.dir == DIR_UP || tank.dir == DIR_DOWN) { // 上下
                    if (x + RADIUS >= tank.x && x + RADIUS <= tank.x + RADIUS
                            && y - RADIUS >= tank.y - RADIUS && y - RADIUS <= tank.y + RADIUS) {
                        return true;
                    }
                    if (x + RADIUS >= tank.x - RADIUS && x + RADIUS <= tank.x + RADIUS
                            && y + RADIUS >= tank.y && y + RADIUS <= tank.y + RADIUS) {
                        return true;
                    }
                } else { // 左右
                    if (x + RADIUS >= tank.x - RADIUS && x + RADIUS <= tank.x + RADIUS
                            && y - RADIUS >= tank.y - RADIUS && y - RADIUS <= tank.y + RADIUS) {
                        return true;
                    }
                    if (x + RADIUS >= tank.x - RADIUS && x + RADIUS <= tank.x + RADIUS
                            && y + RADIUS >= tank.y - RADIUS && y + RADIUS <= tank.y + RADIUS) {
                        return true;
                    }
                }
            } else {
                if (tank.dir == DIR_UP || tank.dir == DIR_DOWN) { // 上下
                    if (x + RADIUS >= tank.x - RADIUS && x + RADIUS <= tank.x + RADIUS
                            && y - RADIUS >= tank.y - RADIUS && y - RADIUS <= tank.y + RADIUS) {
                        return true;
                    }
                    if (x + RADIUS >= tank.x - RADIUS && x + RADIUS <= tank.x + RADIUS
                            && y + RADIUS >= tank.y - RADIUS && y + RADIUS <= tank.y + RADIUS) {
                        return true;
                    }
                } else { // 左右
                    if (x + RADIUS >= tank.x - RADIUS && x + RADIUS <= tank.x + RADIUS
                            && y - RADIUS >= tank.y - RADIUS && y - RADIUS <= tank.y + RADIUS) {
                        return true;
                    }
                    if (x + RADIUS >= tank.x && x + RADIUS <= tank.x + RADIUS
                            && y + RADIUS >= tank.y && y + RADIUS <= tank.y + RADIUS) {
                        return true;
                    }
                }
            }
        }
        return false;
    }*/

    private long fireTime;

    /**
     * 开火
     */
    public void fire() {
        long millis = System.currentTimeMillis();
        if (millis - fireTime < 100 || bullets.size() > 2) return;
        int bulletX = x;
        int bulletY = y;
        switch (dir) {
            case DIR_UP:
                bulletY -= RADIUS;
                break;
            case DIR_DOWN:
                bulletY += RADIUS;
                break;
            case DIR_LEFT:
                bulletX -= RADIUS;
                break;
            case DIR_RIGHT:
                bulletX += RADIUS;
                break;
        }
        // 对象池获取，并初始化坐标等
        Bullet bullet = BULLET_POOL.get();
        bullet.setX(bulletX);
        bullet.setY(bulletY);
        bullet.setDir(dir);
        bullet.setColor(color);
        bullet.setVisible(true);
        bullets.add(bullet);
        if (!(this instanceof EnemyTank)) Audio.playFire();
        fireTime = millis;
    }

    private void drawTank(Graphics g) {
        g.setColor(Color.white);
        g.drawString(name, x - RADIUS, y - RADIUS - BloodBar.BAR_HEIGHT * 3);
        if (this instanceof EnemyTank) {
            g.drawImage(enemyImages[dir], x - RADIUS, y - RADIUS, RADIUS << 1, RADIUS << 1, null);
            ((EnemyTank) this).ai();
        } else {
            g.drawImage(heroImages[dir], x - RADIUS, y - RADIUS, RADIUS << 1, RADIUS << 1, null);
        }
    }

    public void drawBullets(Graphics g) {
        for (int i = 0; i < bullets.size(); i++) {
            Bullet bullet = bullets.get(i);
            if (bullet.isVisible()) {
                bullet.draw(g);
            } else {
                BULLET_POOL.ret(bullet);
                bullets.remove(bullet);
            }
        }
    }

    private void logic() {
        switch (state) {
            case STATE_STAND:
                break;
            case STATE_MOVE:
                move();
                break;
            case STATE_DIE:
                break;
        }
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    public int getDir() {
        return dir;
    }

    public void setDir(int dir) {
        this.dir = dir;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
    }

    public boolean isVisible() {
        return visible;
    }

    public void setVisible(boolean visible) {
        this.visible = visible;
    }

    public List<Bullet> getBullets() {
        return bullets;
    }

    public int getHp() {
        return hp;
    }

    public void setHp(int hp) {
        this.hp = hp;
    }

    /**
     * 血条
     */
    class BloodBar {
        public static final int BAR_LENGTH = RADIUS << 1;
        public static final int BAR_HEIGHT = 5;

        public void draw(Graphics g) {
            g.setColor(Color.YELLOW); // 黄色底色
            g.fillRect(x - RADIUS, y - RADIUS - BAR_HEIGHT * 2, BAR_LENGTH, BAR_HEIGHT);
            g.setColor(Color.RED); // 红色血条
            g.fillRect(x - RADIUS, y - RADIUS - BAR_HEIGHT * 2, hp * BAR_LENGTH / DEFAULT_HP, BAR_HEIGHT);
            g.setColor(Color.WHITE); // 白色边框
            g.drawRect(x - RADIUS, y - RADIUS - BAR_HEIGHT * 2, BAR_LENGTH, BAR_HEIGHT);
        }
    }

    @Override
    public String toString() {
        return "Tank{" +
                "x=" + x +
                ", y=" + y +
                ", dir=" + dir +
                ", name='" + name + '\'' +
                ", visible=" + visible +
                ", preX=" + preX +
                ", preY=" + preY +
                '}';
    }
}

/**
 * 敌方坦克
 */
class EnemyTank extends Tank {

    private long aiTime;

    public EnemyTank() {
        super();
    }

    public EnemyTank(int x, int y, int dir) {
        super(x, y, dir, "");
        aiTime = System.currentTimeMillis();
    }

    public void ai() {
        long millis = System.currentTimeMillis();
        if (millis - aiTime > ENEMY_AI_INTERVAL) {
            aiTime = millis;
            int[] dirs; // 定义改变方向的范围
            if (getY() <= RADIUS + MyFrame.TOP + Tank.BloodBar.BAR_HEIGHT * 6) {
                dirs = new int[]{DIR_DOWN, DIR_LEFT, DIR_RIGHT};
            } else if (getY() + RADIUS >= FRAME_HEIGHT) {
                dirs = new int[]{DIR_UP, DIR_LEFT, DIR_RIGHT};
            } else if (getX() <= RADIUS) {
                dirs = new int[]{DIR_UP, DIR_DOWN, DIR_RIGHT};
            } else if (getX() + RADIUS >= FRAME_WIDTH) {
                dirs = new int[]{DIR_UP, DIR_DOWN, DIR_LEFT};
            } else {
                dirs = new int[]{DIR_UP, DIR_DOWN, DIR_LEFT, DIR_RIGHT};
            }
            setDir(dirs[RandomUtil.randomInt(dirs.length)]);
            setState(RandomUtil.randomInt(2));
        }
        if (RandomUtil.randomDouble() < ENEMY_FIRE_PERCENT) {
            fire();
        }
    }

}

/**
 * 子弹
 */
class Bullet {
    public static final int RADIUS = 4;
    public static final int DEFAULT_SPEED = Tank.DEFAULT_SPEED << 1;

    private int x, y;
    private int dir;
    private int atk = RandomUtil.randomInt(100, 1001);
    private int speed = DEFAULT_SPEED;
    private Color color;
    private boolean visible = true;

    public Bullet() {

    }

    public void draw(Graphics g) {
        g.setColor(color);
        g.fillOval(x - RADIUS, y - RADIUS, RADIUS << 1, RADIUS << 1);
        logic();
    }

    public Rectangle getRect() {
        return new Rectangle(x - RADIUS, y - RADIUS, RADIUS << 1, RADIUS << 1);
    }

    public void logic() {
        move();
    }

    private void move() {
        switch (dir) {
            case Tank.DIR_UP:
                y -= speed;
                break;
            case Tank.DIR_DOWN:
                y += speed;
                break;
            case Tank.DIR_LEFT:
                x -= speed;
                break;
            case Tank.DIR_RIGHT:
                x += speed;
                break;
        }
        if (x < 0 || x > FRAME_WIDTH || y < 0 || y > FRAME_HEIGHT) visible = false;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    public void setDir(int dir) {
        this.dir = dir;
    }

    public int getAtk() {
        return atk;
    }

    public void setAtk(int atk) {
        this.atk = atk;
    }

    public void setColor(Color color) {
        this.color = color;
    }

    public boolean isVisible() {
        return visible;
    }

    public void setVisible(boolean visible) {
        this.visible = visible;
    }
}

/**
 * 爆炸
 */
class Boom {
    private static final Image[] booms = new Image[16];

    static {
        for (int i = 0; i < booms.length; i++) {
            booms[i] = getImage("/static/e" + (i + 1) + ".gif");
        }
    }

    private int x;
    private int y;
    private int life = 0;
    private int width = booms[0].getWidth(null);
    private int height = booms[0].getHeight(null);

    public Boom(int x, int y) {
        this.x = x;
        this.y = y;
        Audio.playBomb();
    }

    public void draw(Graphics g) {
        if (life < booms.length) {
            g.drawImage(booms[life++], x - Tank.RADIUS, y - Tank.RADIUS, null);
        }
    }

    public int getLife() {
        return life;
    }
}
